package cipher.algorithm;

import java.util.ArrayList;
import java.util.Random;

public class Lfsr extends Algorithm {
	
	private int size;
	private int registre;
	private int retroaction;
	
	public Lfsr(){
		this.size = 0;
		this.registre = 0;
		this.retroaction = 0;
	}
	
	public Lfsr(int size, String registre, String retroaction) {
		if(size > 0 && size < 32 && registre.length() == size){
			this.size = size;
			Algorithm.setKEY_LENGTH(size);
			this.registre = stringtoInt32(registre,registre.length());
			this.retroaction = stringtoInt32(retroaction,retroaction.length());
		}
		else	System.out.println("LFSR_INIT_ERR");
	}

	public Lfsr(int size, int registre, int retroaction){
		if(size > 0 && size < 32 && Integer.toBinaryString(registre).length() == size){
			this.size = size;
			Algorithm.setKEY_LENGTH(size);
			this.registre = registre;
			this.retroaction = retroaction;
		}
		else	System.out.println("LFSR_INIT_ERR");
	}
	
	public ArrayList<String> generateNewKey(int keySize){
		ArrayList<String> key = new ArrayList<String>();
		String registre = "";
		String retroaction = "";
		int i, size = keySize;
		float number;
		Random rand = new Random();
		rand.setSeed(System.currentTimeMillis());

			for(i = size; i > 0; i--){
				number = rand.nextFloat();
				if(number >= 0.5)	registre += '1';
				else	registre += '0';

				number = rand.nextFloat();
				if(number >= 0.5)	retroaction += '1';
				else	retroaction += '0';
			}

			retroaction = '1'+retroaction;
			retroaction += '1';
			
			key.add(registre);
			key.add(retroaction);
			
		return key;
	}
	
	public int generateNextNumber() {
		return 0;
	}

	public int generateNextNumber(int length) {
		int i, j, key = 0, exit_val;

			for(i = length-1; i >= 0; i--){
				//dernier bit du registre dans key
				exit_val = readBit(this.registre,this.size-1);
				switch(exit_val){
					case 0 : key = write0(key,i); break;
					case 1 : key = write1(key,i); break;
				}

				//calcul de la nouvelle valeur à entrer dans le registre
				for(j = this.size-1; j > 0; j--){
					if(readBit(this.retroaction,j) == 1)	exit_val ^= readBit(this.registre,j-1);
				}

				//décalage du registre
				this.registre *= 2;

				//nouvelle valeur du registre
				switch(exit_val){
					case 0 : this.registre = write0(this.registre,0); break;
					case 1 : this.registre = write1(this.registre,0); break;
				}
			}

			return key;
	}

	public int getSize() {	return size;	}
	public int getRegistre() {	return registre;	}
	public int getRetroaction() {	return retroaction;	}
	
	public void setSize(int size) {	this.size = size;	}
	public void setRegistre(int registre) {	this.registre = registre;	}
	public void setRetroaction(int retroaction) {	this.retroaction = retroaction;	}

	public String toString(){
		String str = "";
		String tmp = "";
		str += "\tSize: "+this.size+"\n";
		
		for(int i = this.size-1; i >= 0; i--)	tmp += readBit(this.registre,i);
		str += "\tRegistre: "+tmp+"\n";
		
		tmp = "";
		for(int i = this.size; i >= 0; i--)	tmp += readBit(this.retroaction,i);
		str += "\tRetroaction: "+Integer.toBinaryString(this.retroaction)+"\n";
		
		return str;
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		//Lfsr lfsr = new Lfsr(16, "1100100011101011", "10110111001010111");
		//Lfsr lfsr = new Lfsr(16, 39999, 39999);
		Lfsr lfsr = new Lfsr(8, 175, 241);
		System.out.println(lfsr.toString());
		
		int key = lfsr.generateNextNumber(16);
		System.out.println("Key: "+Integer.toBinaryString(key));
		System.out.println(lfsr.toString());
		//System.out.println(readBit(lfsr.registre,lfsr.size-1));
		
		ArrayList<String> init = ((Algorithm)lfsr).generateNewKey(15);
		System.out.println("Registre: "+init.get(0)+"\nRetroaction: "+init.get(1));
	}

}
